﻿#region File Description
//-----------------------------------------------------------------------------
// EditorScreen.cs
//
// Attack of the Crazy Pixels
// Copyright (c) VosSoft 2009
//-----------------------------------------------------------------------------
#endregion

#region Using Statements
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Xml;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Audio;
using Microsoft.Xna.Framework.Content;
using Microsoft.Xna.Framework.GamerServices;
using Microsoft.Xna.Framework.Graphics;
using Microsoft.Xna.Framework.Input;
using Microsoft.Xna.Framework.Media;
using Microsoft.Xna.Framework.Net;
using Microsoft.Xna.Framework.Storage;
#endregion

namespace Attack_of_the_Crazy_Pixels
{
    /// <summary>
    /// This screen implements the actual game logic.
    /// </summary>
    class EditorScreen : GameScreen
    {
        #region Fields

        const float collisionDistance = 14.0f;

        ContentManager content;

        SpriteFont arial;

        Vector2 mousePosition = Vector2.Zero;

        XmlDocument xmlDoc;
        string xmlFile;
        Polygone path = new Polygone(false, new Vector2(-1000.0f));
        List<Vector2> pathPoints = new List<Vector2>();
        Vector2? selectedPoint = null;
        bool isDragging = false, hasChanged = false, isSaved = false;

        string backgroundFile;
        Texture2D backgroundTexture = null;
        Sprite backgroundSprite = null;

        #endregion

        #region Initialization

        /// <summary>
        /// Constructor.
        /// </summary>
        public EditorScreen()
        {
            TransitionOnTime = TimeSpan.FromSeconds(1.0);
            TransitionOffTime = TimeSpan.FromSeconds(0.5);

            Mouse.SetPosition(640, 360);
        }

        /// <summary>
        /// Load graphics content for the game.
        /// </summary>
        public override void LoadContent()
        {
            if (content == null)
            {
                content = new ContentManager(ScreenManager.Game.Services, "Content");
            }

            arial = content.Load<SpriteFont>(@"Fonts\Arial");

            ScreenManager.Game.IsMouseVisible = true;
            ScreenManager.Game.ResetElapsedTime();
        }

        /// <summary>
        /// Unload graphics content used by the game.
        /// </summary>
        public override void UnloadContent()
        {
            content.Unload();
            ScreenManager.Game.IsMouseVisible = false;
        }

        #endregion

        #region Update and Draw

        /// <summary>
        /// Updates the state of the game. This method checks the GameScreen.IsActive
        /// property, so the game will stop updating when the pause menu is active,
        /// or if you tab away to a different application.
        /// </summary>
        public override void Update(GameTime gameTime, bool otherScreenHasFocus,
                                                       bool coveredByOtherScreen)
        {
            base.Update(gameTime, otherScreenHasFocus, coveredByOtherScreen);

            if (IsActive)
            {
                if (hasChanged)
                {
                    if (pathPoints.Count > 0)
                    {
                        path = new Polygone(2.0f, Color.Black, false, pathPoints.ToArray());
                    }
                    else
                    {
                        path = new Polygone(false, new Vector2(-1000.0f));
                    }
                    hasChanged = false;
                }
            }
        }

        /// <summary>
        /// Lets the game respond to player input. Unlike the Update method,
        /// this will only be called when the gameplay screen is active.
        /// </summary>
        public override void HandleInput(InputState input)
        {
            if (input.IsPauseGame())
            {
                ScreenManager.AddScreen(new PauseMenuScreen());
            }
            else
            {
                mousePosition = input.CurrentMousePosition;

                if (input.CurrentMouseState.LeftButton == ButtonState.Pressed)
                {
                    if (!isDragging)
                    {
                        selectedPoint = null;
                        foreach (Vector2 point in pathPoints)
                        {
                            if ((point - mousePosition).Length() < collisionDistance)
                            {
                                selectedPoint = point;
                                break;
                            }
                        }
                    }

                    if (selectedPoint == null)
                    {
                        if (input.IsNewButtonPress(MouseButtons.LeftButton))
                        {
                            foreach (Line line in path.Lines)
                            {
                                if (Calc.DistancePointLine(mousePosition, line) < collisionDistance)
                                {
                                    pathPoints.Insert(pathPoints.IndexOf(line.EndPoint), mousePosition);
                                    hasChanged = true;
                                }
                            }
                            if (!hasChanged)
                            {
                                pathPoints.Add(mousePosition);
                                hasChanged = true;
                            }
                            selectedPoint = mousePosition;
                        }
                    }
                    else
                    {
                        pathPoints[pathPoints.IndexOf((Vector2)selectedPoint)] = mousePosition;
                        selectedPoint = mousePosition;
                        isDragging = true;
                        hasChanged = true;
                    }
                }
                else
                {
                    isDragging = false;
                }

                if (input.CurrentKeyboardState.IsKeyDown(Keys.LeftControl))
                {
                    if (input.IsNewKeyPress(Keys.Delete))
                    {
                        pathPoints.Clear();
                        hasChanged = true;
                    }
                    else if (input.IsNewKeyPress(Keys.S))
                    {
                        xmlDoc = new XmlDocument();
                        xmlFile = @"Content\Levels\new.xml";
                        xmlDoc.AppendChild(xmlDoc.CreateXmlDeclaration("1.0", "utf-8", null));
                        xmlDoc.AppendChild(xmlDoc.CreateComment("This level was created with the ACP Level Editor v0.1a at "
                            + DateTime.Now.ToString()));
                        XmlElement elementLevel = xmlDoc.CreateElement("level");
                        XmlElement elementPath = xmlDoc.CreateElement("path");
                        XmlElement elementPoint;
                        foreach (Vector2 point in pathPoints)
                        {
                            elementPoint = xmlDoc.CreateElement("point");
                            elementPoint.SetAttribute("x", point.X.ToString());
                            elementPoint.SetAttribute("y", point.Y.ToString());
                            elementPath.AppendChild(elementPoint);
                        }
                        elementLevel.AppendChild(elementPath);
                        xmlDoc.AppendChild(elementLevel);
                        xmlDoc.Save(xmlFile);
                        isSaved = true;
                    }
                }
                else if (input.IsNewKeyPress(Keys.Delete) && selectedPoint != null)
                {
                    pathPoints.Remove((Vector2)selectedPoint);
                    selectedPoint = null;
                    hasChanged = true;
                }
                else if (input.IsNewKeyPress(Keys.B))
                {
                    backgroundFile = @"Content\Textures\Levels\background.png";
                    if (File.Exists(backgroundFile))
                    {
                        backgroundTexture = Texture2D.FromFile(ScreenManager.GraphicsDevice, backgroundFile);
                        backgroundSprite = new Sprite(backgroundTexture, Vector2.Zero, ScreenManager.GraphicsDevice.Viewport.TitleSafeArea,
                            Color.White, 0.0f, Vector2.Zero, Vector2.One, SpriteEffects.None, 0.0f);
                    }
                }
            }
        }

        /// <summary>
        /// Draws the gameplay screen.
        /// </summary>
        public override void Draw(GameTime gameTime)
        {
            float elapsedTime = (float)gameTime.ElapsedGameTime.TotalSeconds;
            ScreenManager.GraphicsDevice.Clear(ClearOptions.Target, Color.White, 0.0f, 0);

            SpriteManager.Begin();

            if (backgroundSprite != null)
            {
                SpriteManager.Draw(backgroundSprite);
            }

            if (pathPoints.Count > 0)
            {
                foreach (Line line in path.Lines)
                {
                    SpriteManager.Draw(line.LineSprite);
                }
                foreach (Vector2 point in path.Points)
                {
                    SpriteManager.Draw(new Sprite(SpriteManager.BlankTexture, point, null, Color.Blue, 0.0f,
                        new Vector2(0.5f), new Vector2(10.0f), SpriteEffects.None, 0.0f));
                }
            }

            SpriteManager.SpriteBatch.DrawString(arial, "Level Editor 0.1a\n"
                + "# Points: " + pathPoints.Count.ToString()+ "\n"
                + "SelectedPoint = " + selectedPoint,
                new Vector2(10.0f), Color.Black);

            if (isSaved)
            {
                SpriteManager.SpriteBatch.DrawString(arial, "Level saved => " + xmlFile, new Vector2(10.0f, 700.0f), Color.Black);
            }

            SpriteManager.End();

            // If the game is transitioning on or off, fade it out to black.
            if (TransitionPosition > 0)
            {
                ScreenManager.FadeBackBufferToBlack(255 - TransitionAlpha);
            }
        }

        #endregion
    }
}
